package utils

import (
	"archive/zip"
	"os"
	"io"
	"strings"
	"log"
	"path/filepath"
	"bytes"
	"golang.org/x/text/transform"
	"golang.org/x/text/encoding/simplifiedchinese"
	"io/ioutil"
	"path"
)

func UnZip(src, dst string) (string, error) {
	reader, err := zip.OpenReader(src)
	if err != nil {
		log.Fatal(err)
		return "", &ZipError{err.Error()}
	}
	defer reader.Close()

	zipFullName := path.Base(src)
	zipSuffix := path.Ext(zipFullName)
	zipDirName := strings.TrimSuffix(zipFullName, zipSuffix)

	for _, f := range reader.File {
		rc, err := f.Open()
		if err != nil {
			log.Fatal(err)
			return "", &ZipError{err.Error()}
		}
		defer rc.Close()

		i := bytes.NewReader([]byte(f.Name));
		decoder := transform.NewReader(i, simplifiedchinese.GBK.NewDecoder())
		fileName, _ := ioutil.ReadAll(decoder)
		fullFilePath := filepath.Join(dst, "/", zipDirName, "/", string(fileName))

		if f.FileInfo().IsDir() {
			err = os.MkdirAll(fullFilePath, 0755)
			if err != nil {
				log.Fatal(err)
				return "", &ZipError{err.Error()}
			}
		} else {
			var fdir string
			if lastIndex := strings.LastIndex(fullFilePath, string(os.PathSeparator)); lastIndex > -1 {
				fdir = fullFilePath[:lastIndex]
			}

			if len(f.Name) < 150 {
				err = os.MkdirAll(fdir, 0755)
				if err != nil {
					log.Fatal(err)
					return "", &ZipError{err.Error()}
				}

				fi, err := os.OpenFile(fullFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
				if err != nil {
					log.Fatal(err)
					return "", &ZipError{err.Error()}
				}

				defer fi.Close()

				_, err = io.Copy(fi, rc)
				if err != nil {
					log.Fatal(err)
					return "", &ZipError{err.Error()}
				}
			}
		}
	}

	return strings.Join([]string{dst, zipDirName}, "/"), nil
}

type ZipError struct {
	Msg string
}

func (e *ZipError) Error() string {
	return "unzip: when unzip happen error, " + e.Msg
}
